﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using cmdb.keede.common;
using cmdb.keede.data;
using cmdb.keede.entity;
using Microsoft.EntityFrameworkCore;

namespace cmdb.keede.service
{
    public class BusinessTopologyService : IBusinessTopologyService
    {
        private readonly IEnvironmentInfoRepository _envRepository;
        private readonly IBusinessInfoRepository _businessRepository;
        private readonly IApplicationInfoRepository _appRepository;
        private readonly IApplicationHostRepository _appHostRepository;

        public BusinessTopologyService(IEnvironmentInfoRepository envRepository, IBusinessInfoRepository businessRepository, IApplicationInfoRepository appReposiotry, IApplicationHostRepository appHostRepository)
        {
            _envRepository = envRepository;
            _businessRepository = businessRepository;
            _appRepository = appReposiotry;
            _appHostRepository = appHostRepository;
        }

        //public async Task<BizResult<List<TreeNode>>> GetEnvironmentNodesAsync()
        //{
        //    var result = await _envRepository.GetManyAsync(w => w.Status == EnumEnvironmentStatus.Enabled);
        //    var idx = 1;
        //    var nodes = result.Select(env => new TreeNode
        //    {
        //        Id = idx++,
        //        Pid = 0,
        //        Name = env.Name,
        //        BakValue = env.Id.ToString(),
        //        Open = false,
        //        IsParent = true
        //    }).ToList();

        //    return new BizResult<List<TreeNode>>(nodes);
        //}

        public async Task<BizResult<List<TreeNode>>> GetTreeNodesAsync(int level, int parentId = 0, int bakValue = 0)
        {
            if (parentId == 0) return await GetEnvNodesAsync();

            switch (level)
            {
                case 0:
                    return await GetBusinessNodesAsync(bakValue, parentId);
                case 1:
                    return await GetApplicationNodesAsync(bakValue, parentId);
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        public async Task<BizResult<List<VirtualHostInfo>>> GetVirtualHostsByAppIdAsync(int applicationId, int pageIndex, int pageSize)
        {
            var query = _appHostRepository.GetQueryable(w => w.ApplicationId == applicationId);
            var vhquery = query.Select(s => s.VirtualHost).OrderBy(o => o.Id);

            var pager = new Pager(pageIndex, pageSize);
            var queryPage = vhquery.GetPageWithTotalCount(ref pager);

            return new BizResult<List<VirtualHostInfo>>(await queryPage.ToListAsync(), pager);
        }

        public async Task<BizResult<List<VirtualHostInfo>>> SearchVirtualHostsAsync(int applicationId, string innerIP, string outerIP, EnumOperationSystem? os, EnumVirtualHostStatus? status, int pageIndex, int pageSize)
        {
            var query = _appHostRepository.GetQueryable(w => w.ApplicationId == applicationId);
            var vhquery = query.Select(s => s.VirtualHost).Where(w => (string.IsNullOrEmpty(innerIP) || w.InnerIP.Contains(innerIP))
                                                            && (string.IsNullOrEmpty(outerIP) || w.InnerIP.Contains(outerIP))
                                                            && (!os.HasValue || w.OS == os.Value)
                                                            && (!status.HasValue || w.Status == status.Value))
                                                          .OrderBy(o => o.Id);

            var pager = new Pager(pageIndex, pageSize);
            var queryPage = vhquery.GetPageWithTotalCount(ref pager);

            return new BizResult<List<VirtualHostInfo>>(await queryPage.ToListAsync(), pager);
        }

        #region private method
        private async Task<BizResult<List<TreeNode>>> GetEnvNodesAsync()
        {
            var result = await _envRepository.GetManyAsync(w => w.Status == EnumEnvironmentStatus.Enabled);
            var idx = 1;
            var nodes = result.Select(env => new TreeNode
            {
                Id = idx++,
                Pid = 0,
                Name = env.Name,
                BakValue = env.Id.ToString(),
                Open = false,
                IsParent = true
            }).ToList();

            return new BizResult<List<TreeNode>>(nodes);
        }

        private async Task<BizResult<List<TreeNode>>> GetBusinessNodesAsync(int envId, int parentId)
        {
            var result = await _businessRepository.GetManyAsync(w => w.Status == EnumBusinessStatus.Enabled && w.EnvironmentId == envId);

            var idx = 1;
            var nodes = result.Select(b => new TreeNode
            {
                Id = idx++,
                Pid = parentId,
                Name = b.Name,
                BakValue = b.Id.ToString(),
                Open = false,
                IsParent = true
            }).ToList();

            return new BizResult<List<TreeNode>>(nodes);
        }

        private async Task<BizResult<List<TreeNode>>> GetApplicationNodesAsync(int businessId, int parentId)
        {
            var result = await _appRepository.GetManyAsync(w => w.BusinessId == businessId && w.Status == EnumApplicationStatus.Enabled);

            var idx = 1;
            var nodes = result.Select(app => new TreeNode
            {
                Id = idx++,
                Pid = parentId,
                Name = app.Name,
                BakValue = app.Id.ToString(),
                Open = false,
                IsParent = false
            }).ToList();

            return new BizResult<List<TreeNode>>(nodes);
        }
        #endregion
    }
}